package bonecp.bonecp_src_read;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.jolbox.bonecp.BoneCPConfig;

/**
 * Hello world!
 *
 */
public class App 
{
	private static final Logger logger = LoggerFactory.getLogger(App.class);

    public static void main( String[] args )
    {
    	App app = new App();
    	String filename = "bonecp-default-config.xml";
    	app.loadProperties(filename);
    }
    
    private void loadProperties(String filename)
    {
		ClassLoader thclassLoader = Thread.currentThread().getContextClassLoader();
		if (thclassLoader != null){
			URL url = thclassLoader.getResource(filename);
			if (url != null){
				try {
					this.setXMLProperties(url.openStream(), null);
				} catch (Exception e) {
					// do nothing
				} 
			}
		}
    }
    
    
    private void setXMLProperties(InputStream xmlConfigFile, String sectionName)
			throws Exception {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db;
		// ugly XML parsing, but this is built-in the JDK.
		try {
			db = dbf.newDocumentBuilder();
			Document doc = db.parse(xmlConfigFile);
			doc.getDocumentElement().normalize();

			// get the default settings
			Properties settings = parseXML(doc, null);
			
			//调试代码
			for(Object key : settings.keySet()){
				System.out.println(key+"---"+settings.get(key));
			}
			
			
			if (sectionName != null){
				// override with custom settings
				settings.putAll(parseXML(doc, sectionName));
			}
			
			// set the properties
			setProperties(settings);

		} catch (Exception e) {
			throw e;
		} finally {
			if (xmlConfigFile != null){ // safety
				xmlConfigFile.close();
			}
		}
	}   
    
    
    private Properties parseXML(Document doc, String sectionName) {
		int found = -1;
		Properties results = new Properties();
		NodeList config = null;
		if (sectionName == null){
			config = doc.getElementsByTagName("default-config");
			found = 0;
		} else {
			config = doc.getElementsByTagName("named-config");
			if(config != null && config.getLength() > 0) {
				for (int i = 0; i < config.getLength(); i++) {
					Node node = config.item(i);
					if(node.getNodeType() == Node.ELEMENT_NODE ){
						NamedNodeMap attributes = node.getAttributes();
						if (attributes != null && attributes.getLength() > 0){
							Node name = attributes.getNamedItem("name");
							if (name.getNodeValue().equalsIgnoreCase(sectionName)){
								found = i;
								break;
							}
						}
					}
				}
			}

			if (found == -1){
				config = null;
				logger.warn("Did not find "+sectionName+" section in config file. Reverting to defaults.");
			}
		}

		if(config != null && config.getLength() > 0) {
			Node node = config.item(found);
			if(node.getNodeType() == Node.ELEMENT_NODE){
				Element elementEntry = (Element)node;
				NodeList childNodeList = elementEntry.getChildNodes();
				for (int j = 0; j < childNodeList.getLength(); j++) {
					Node node_j = childNodeList.item(j);
					if (node_j.getNodeType() == Node.ELEMENT_NODE) {
						Element piece = (Element) node_j;
						NamedNodeMap attributes = piece.getAttributes();
						if (attributes != null && attributes.getLength() > 0){
							results.put(attributes.item(0).getNodeValue(), piece.getTextContent());
						}
					}
				}
			}
		}

		return results;
	}
    
    
    public void setProperties(Properties props) throws Exception {
		// Use reflection to read in all possible properties of int, String or boolean.
		for (Method method: BoneCPConfig.class.getDeclaredMethods()){
			String tmp = null;
			if (method.getName().startsWith("is")){
				tmp = lowerFirst(method.getName().substring(2));
			} else if (method.getName().startsWith("set")){
				tmp = lowerFirst(method.getName().substring(3));
			} else {
				continue;
			}

			if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(int.class)){
				String val = props.getProperty(tmp);
				
				if (val == null){
					val = props.getProperty("bonecp."+tmp); // hibernate provider style
				}
				if (val != null) {
					try{
						method.invoke(this, Integer.parseInt(val));
					} catch (NumberFormatException e){
						// do nothing, use the default value
					}
				}
			} else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(long.class)){
				String val = props.getProperty(tmp);
				if (val == null){
					val = props.getProperty("bonecp."+tmp); // hibernate provider style
				}
				if (val != null) {
					try{
						method.invoke(this, Long.parseLong(val));
					} catch (NumberFormatException e){
						// do nothing, use the default value
					}
				}
			} else if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(String.class)){
				String val = props.getProperty(tmp);
				if (val == null){
					val = props.getProperty("bonecp."+tmp); // hibernate provider style
				}
				if (val != null) {
					method.invoke(this, val);
				}
			} if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(boolean.class)){
				String val = props.getProperty(tmp);
				if (val == null){
					val = props.getProperty("bonecp."+tmp); // hibernate provider style
				}
				if (val != null) {
					method.invoke(this, Boolean.parseBoolean(val));
				}
			}
		}
	}

	private String lowerFirst(String name) {
		return name.substring(0, 1).toLowerCase()+name.substring(1);
	}
}
